/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package id3;

import java.util.ArrayList;

/**
 *
 * @author SONY VAIO
 */
public class Tree {
     private ArrayList<Record> records;
     private ArrayList<Record> testrecords;
     private ArrayList<String> hasilInferensi;

     public Tree(ArrayList<Record> data, ArrayList<Record> data_test){
         this.records = data;
         this.testrecords = data_test;
     }

     public void classify(){
         Node root = new Node();

         // Inisialisasi Komponen Node
        for(Record record : records){
            root.data.add(record);
        }

        root = buildTree(records, root);
        hasilInferensi = Utility.Inference(testrecords, root);
//        PrintTree(root);
//        for(int i = 0; i < hasilInferensi.size(); ++i){
//            System.out.println("Record " + i + " = " + hasilInferensi.get(i));
//        }
     }

    public ArrayList<String> get_hasil_inferensi()
    {
        return hasilInferensi;
    }

    public Node buildTree(ArrayList<Record> records, Node root) {
        int bestAttribute = -1;
        double bestGain = 0;
        root.entropy = Utility.calculateEntropy(root.data);

        if (root.entropy == 0) {
            root.rootName = Utility.attributeDetails.get(Utility.ATTRIBUTE_NUM-1).nama;
            root.className = Utility.getClassName(root);
            return root;
        }

        // Mendapatkan atribut terbaik berdasarkan information gain
        for (int i = 0; i < Utility.ATTRIBUTE_NUM - 1; ++i) {
            if (!Utility.isAttributeUsed(i,root)) {
                double entropy = 0;
                ArrayList<Double> entropies = new ArrayList<Double>();
                ArrayList<Integer> subSizes = new ArrayList<Integer>();

                // Mendapatkan sub entropy untuk masing-masing value dari atribut yang
                // akan digunakan untuk menghitung gain
                for (int j = 0; j < Utility.attributeDetails.get(i).list_value.size(); ++j) {
                    String attributeDetailsValue = Utility.attributeDetails.get(i).list_value.get(j);
                    ArrayList<Record> subset = subset(root, i, attributeDetailsValue);
                    subSizes.add(subset.size());
                        
                    if (subset.size() != 0) {
                        entropy = Utility.calculateEntropy(subset);
                        entropies.add(entropy);
                    }
                }

                double gain = Utility.calculateGain(root.entropy, entropies, subSizes, root.data.size());

                if (gain > bestGain) {
                    bestAttribute = i;
                    bestGain = gain;
                }
            }
        }


        if (bestAttribute != -1) {
            int size = Utility.attributeDetails.get(bestAttribute).list_value.size();
            root.childrenCount = size;
            root.children = new Node[size];
            root.isUsed = true;
            //root.testAttribute.name = Utility.attributeDetails.get(bestAttribute).nama;
            root.rootName = Utility.attributeDetails.get(bestAttribute).nama;
            root.usedAttributes_id.add(bestAttribute);

            //Memperluas cabang pohon
            for (int j = 0; j < size; ++j) {
                root.children[j] = new Node();
                root.children[j].parent = root;
                root.children[j].data = subset(root, bestAttribute, Utility.attributeDetails.get(bestAttribute).list_value.get(j));
                //root.children[j].testAttribute.value = Utility.attributeDetails.get(bestAttribute).list_value.get(j);
                root.children[j].arrowName = Utility.attributeDetails.get(bestAttribute).list_value.get(j);
                
                // Copy Used Attributes Id
                for(int k = 0; k < root.usedAttributes_id.size(); ++k){
                    root.children[j].usedAttributes_id.add(root.usedAttributes_id.get(k));
                }
            }

            for (int j = 0; j < size; ++j) {
                buildTree(root.children[j].data, root.children[j]);
            }

            root.data = null;

        } else {
            return root;
        }

        return root;
    }

    public ArrayList<Record> subset(Node root, int attribute_id, String value) {
        ArrayList<Record> subset = new ArrayList<Record>();

        for (int i = 0; i < root.data.size(); ++i) {
            Record record = root.data.get(i);
            String recordValue = record.getAttribute().get(attribute_id).value;
            if (recordValue.equalsIgnoreCase(value)) {
                subset.add(record);
            }
        }
        return subset;
    }

    public void PrintTree(Node root) {
        root.PrintNode();
        if (root.childrenCount != 0) {
            for (int i = 0; i < root.childrenCount; ++i) {
                PrintTree(root.children[i]);
            }
        }
    }
}
